use async_trait::async_trait;

use rbatis::RBatis;
use rbatis::crud;
use rbatis::impl_select;
use serde::Deserialize;
use serde::Serialize;
use zen_engine::loader::{LoaderError, LoaderResult};
use zen_engine::model::DecisionContent;

use crate::loader::RulesLoaderExt;

/// 系统加载器，从sqlite数据库加载规则
#[derive(Debug)]
pub struct SqliteLoader {
    conn: Option<RBatis>,
}

#[async_trait]
impl RulesLoaderExt for SqliteLoader {
    async fn load_rule(
        &self,
        key: &str,
    ) -> LoaderResult<DecisionContent> {
        let conn = self.conn.as_ref().unwrap();
        let entity = DecisionContentEntity::select_by_name(conn, key)
            .await
            .map_err(|e| LoaderError::Internal { key: key.to_string(), source: e.into() })?
            .ok_or_else(|| LoaderError::NotFound(key.to_string()))?;
        Ok(entity.into())
    }
}
impl SqliteLoader {
    pub fn new(path: String) -> Self {
        let conn = RBatis::new();
        conn.init(rbdc_sqlite::Driver {}, &format!("sqlite://{}", path)).unwrap();
        Self { conn: Some(conn) }
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DecisionContentEntity {
    pub id: i64,
    pub name: String,
    pub request: Vec<u8>, // 请求参数
    pub nodes: Vec<u8>,   // 节点
    pub edges: Vec<u8>,   // 边
}

crud!(DecisionContentEntity {}, "decision_content");
impl_select!(DecisionContentEntity{select_by_name(name:&str) -> Option => "`where name = #{name} limit 1`"});

// 实现 into 方法
impl From<DecisionContentEntity> for DecisionContent {
    fn from(value: DecisionContentEntity) -> Self {
        DecisionContent { nodes: serde_json::from_slice(&value.nodes).unwrap(), edges: serde_json::from_slice(&value.edges).unwrap() }
    }
}
